package lmteam.applicationservice;

public class AssignmentServiceProcessor 
                        implements IAssignProcess {

  // ctor
  public AssignmentServiceProcessor() {
    _eligible = new java.util.Vector<lmteam.common.User>();
  }

  // primary interface into the service
  public boolean assignTask(lmteam.common.Document inDoc)
        throws java.rmi.RemoteException {

    System.out.println("Calling assignTask");

    // generator to pick random users
    java.util.Random rg = new java.util.Random();

    // Obtain a list of eligible reviewers
    boolean success = loadEligibleUsers(REVIEWER, inDoc);

    // Continue if successful.
    if (success) {

      // Select up to 5 reviewers at random
      lmteam.common.User[] reviewers = new lmteam.common.User[5];
      int selected = 0;
      int idx = 0;

      for (; idx < 5; idx++) {

        // Choose a random slot
        int randInt = rg.nextInt(_eligible.size());
        reviewers[idx] = _eligible.elementAt(randInt);

        // Since this reviewer was just added, remove from the eligible list
        _eligible.removeElementAt(randInt);

        // If there are no more eligible reviewers, step out
        if (_eligible.isEmpty()) break;

      } // select reviewers

      inDoc.setReviewer(reviewers);

    } // reviewers found

    // Obtain list of eligible approvers
    success = (success && loadEligibleUsers(APPROVER, inDoc));

    // Continue if successful
    if (success) {

      // Choose a random slot
      inDoc.setApprover(_eligible.elementAt(rg.nextInt(_eligible.size())));

      success = updateDatabase(inDoc);

    } // approvers found

    return success;

  } // assignTask

  // ---------------------------------------------------------------------------
  // Private member methods
  // ---------------------------------------------------------------------------
  private boolean updateDatabase(lmteam.common.Document doc) {

    boolean success = false;
    lmteam.documentdataservice.IDataAccessServiceLocator locator =
            new lmteam.documentdataservice.IDataAccessServiceLocator();
    String fName = doc.getFilename();

    try {

      lmteam.documentdataservice.IDataAccess dataAccess = locator.getIDataAccess();

      // see if the document we are updating already exists.
      lmteam.common.Document dbDoc = dataAccess.get(fName);

      // If the returned document is NULL, then just add the document we have.
      if (dbDoc == null) {

        System.out.println("Adding " + fName + " to database.");
        dataAccess.add(doc, fName, doc.getAuthor());

      // Otherwise, update the one in the database.
      } else {
      
        // Create a role that is set to true for a reviewer.
        lmteam.common.Role role = new lmteam.common.Role(false, false, false);
        role.setReviewer(true);

        // Retrieve the list of reviewers for the document
        lmteam.common.User reviewers[] = doc.getReviewer();

        // Loop through the list of reviewers and update the database
        for (int idx = 0; idx < reviewers.length; idx++) dataAccess.update(fName, reviewers[idx], role, true);

        // Set role to approver
        role.setReviewer(false);
        role.setApprover(true);
        dataAccess.update(fName, doc.getApprover(), role, true);

      } // document already exists

      success = true;

    } catch(Exception e) {

      e.printStackTrace();

    }

    return success;

  } // updateDatabase

  // Fill the list with users for the specified role.  
  private boolean loadEligibleUsers(int role, lmteam.common.Document doc) 
                throws java.rmi.RemoteException {

    lmteam.userservice.IUserAccessServiceLocator locator =
                new lmteam.userservice.IUserAccessServiceLocator();

    // Ensure the elibigle list is empty to start
    _eligible.removeAllElements();

    try {

      lmteam.userservice.IUserAccess userAccess = locator.getIUserAccess();

      // Retrieve list of users from the database
      lmteam.common.User[] userList = userAccess.getUsers();

      // Create list of users who are eligible for the specified role, excluding
      // those who are listed as "authors")
      if (userList != null) {

        for (int i = 0; i < userList.length; i++) {
  
          boolean eligible = false;
  
          lmteam.common.Role userRole = userList[i].getRole();
          if (role == APPROVER) eligible = userRole.isApprover();
          else if (role == REVIEWER) eligible = userRole.isReviewer();
  
          // Determine which users are eligible but not authors of the
          // specified document
          if (eligible &&
              !userList[i].getUsername().equals(doc.getAuthor())) {
  
            _eligible.add(userList[i]);    
  
          } // user eligible for specified role in this document
  
        } // user loop

      } // received a null user list

    } catch(Exception e) {

      e.printStackTrace();

    } // try/catch

    // Ensure there is at least one user to fulfill the role
    return (!_eligible.isEmpty());

  } // loadEligibleUsers 

  // ---------------------------------------------------------------------------
  // Private member objects
  // ---------------------------------------------------------------------------
  private static final int APPROVER = 0;
  private static final int REVIEWER = 1;
  private static final int REQUIRED_REVIEWERS = 5;
  private static final int REQUIRED_APPROVERS = 1;

  // Temp field used to store users eligible for a given role
  private java.util.Vector<lmteam.common.User> _eligible;

} // AssignmentServiceProcessor
